import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PaymentOrder } from '@/database/entities/payment-order.entity';
import * as crypto from 'crypto';

@Injectable()
export class AlipayService {
  private readonly appId: string;
  private readonly privateKey: string;
  private readonly alipayPublicKey: string;
  private readonly gateway: string = 'https://openapi.alipay.com/gateway.do';

  constructor(private configService: ConfigService) {
    this.appId = this.configService.get('ALIPAY_APP_ID');
    this.privateKey = this.configService.get('ALIPAY_PRIVATE_KEY');
    this.alipayPublicKey = this.configService.get('ALIPAY_PUBLIC_KEY');
  }

  async createPayment(order: PaymentOrder): Promise<string> {
    const bizContent = {
      out_trade_no: order.orderNo,
      total_amount: order.amount.toString(),
      subject: order.description || '商品支付',
      product_code: 'FAST_INSTANT_TRADE_PAY',
    };

    const params = {
      app_id: this.appId,
      method: 'alipay.trade.page.pay',
      charset: 'UTF-8',
      sign_type: 'RSA2',
      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),
      version: '1.0',
      notify_url: `${this.configService.get('BACKEND_URL')}/api/payment/callback/alipay`,
      return_url: `${this.configService.get('FRONTEND_URL')}/payment/result`,
      biz_content: JSON.stringify(bizContent),
    };

    const sign = this.generateSign(params);
    params['sign'] = sign;

    const query = Object.keys(params)
      .map(key => `${key}=${encodeURIComponent(params[key])}`)
      .join('&');

    return `${this.gateway}?${query}`;
  }

  async verifyCallback(params: any): Promise<any> {
    const sign = params.sign;
    delete params.sign;
    delete params.sign_type;

    const sortedParams = Object.keys(params)
      .sort()
      .map(key => `${key}=${params[key]}`)
      .join('&');

    const isValid = this.verifySign(sortedParams, sign);
    
    if (!isValid) {
      throw new Error('支付宝回调签名验证失败');
    }

    return params;
  }

  async refund(order: PaymentOrder, reason?: string): Promise<any> {
    const bizContent = {
      out_trade_no: order.orderNo,
      refund_amount: order.amount.toString(),
      refund_reason: reason || '用户申请退款',
    };

    const params = {
      app_id: this.appId,
      method: 'alipay.trade.refund',
      charset: 'UTF-8',
      sign_type: 'RSA2',
      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),
      version: '1.0',
      biz_content: JSON.stringify(bizContent),
    };

    const sign = this.generateSign(params);
    params['sign'] = sign;

    try {
      // 这里应该发送HTTP请求到支付宝接口
      // 为了演示，返回模拟结果
      return {
        success: true,
        refund_fee: order.amount.toString(),
        out_trade_no: order.orderNo,
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
      };
    }
  }

  private generateSign(params: any): string {
    const sortedParams = Object.keys(params)
      .sort()
      .map(key => `${key}=${params[key]}`)
      .join('&');

    const sign = crypto
      .createSign('RSA-SHA256')
      .update(sortedParams, 'utf8')
      .sign(this.privateKey, 'base64');

    return sign;
  }

  private verifySign(data: string, sign: string): boolean {
    try {
      const verify = crypto.createVerify('RSA-SHA256');
      verify.update(data, 'utf8');
      return verify.verify(this.alipayPublicKey, sign, 'base64');
    } catch (error) {
      return false;
    }
  }
}